From 30ab1c272278baaec07d70e6b3c65937c2bd4fb9 Mon Sep 17 00:00:00 2001 From: "Karl O. Pinc" Date: Wed, 18 Sep 2024 13:22:44 -0500 Subject: [PATCH] Add user interface elements supporting download --- src/pgwui_sql/constants.py | 33 +++++++++ src/pgwui_sql/templates/sql_edit.mak | 104 ++++++++++++++++++++++++++- src/pgwui_sql/views/base.py | 74 +++++++++++++++++++ tests/templates/test_templates.py | 22 +++++- 4 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 src/pgwui_sql/constants.py diff --git a/src/pgwui_sql/constants.py b/src/pgwui_sql/constants.py new file mode 100644 index 0000000..09efa60 --- /dev/null +++ b/src/pgwui_sql/constants.py @@ -0,0 +1,33 @@ +# Copyright (C) 2024 The Meme Factory, Inc. http://www.karlpinc.com/ + +# This file is part of PGWUI_SQL. +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License along with this program. If not, see +# . + +# Karl O. Pinc +# + +'''Constants used by the PGWUI_SQL program. +''' + +# Form values + +ONE_FILE = 'one' +MANY_FILES = 'many' + +# HTML radio button attributes +# (That these exist is a sign that we're not really utilizing our toolset.) +ONE_FILE_VALUE = ONE_FILE +MANY_FILES_VALUE = MANY_FILES diff --git a/src/pgwui_sql/templates/sql_edit.mak b/src/pgwui_sql/templates/sql_edit.mak index 9537cf8..1c977a8 100644 --- a/src/pgwui_sql/templates/sql_edit.mak +++ b/src/pgwui_sql/templates/sql_edit.mak @@ -24,6 +24,17 @@ This template uses the following variables in it's context: sql Text of the sql command(s) + download Download the SQL results + csv_value Value to supply in upload_fmt when csv is checked + tab_value Value to supply in upload_fmt when tab is checked + csv_checked HTML with the state of the csv checkbox + tab_checked HTML with the sate of the tab checkbox + one_file_value Value to supply in download_as when "one file" is checked + many_files_value Value to supply in download_as when "many files" + is checked + one_file_checked HTML with the state of the "one file" checkbox + many_files_checked HTML with the state of the "many files" checkbox + include_sql Include SQL in the downloaded results @@ -112,7 +123,7 @@ <%self.lib:td_label for_id="upload_sql_id"> Execute SQL from a file - <%self.lib:td_input tab_index="${tab_index}" clas="search_path_data"> + <%self.lib:td_input tab_index="${tab_index}"> +<%def name="download_row(tab_index)"> + + <%self.lib:td_label for_id="download_id"> + Download + + <%self.lib:td_input tab_index="${tab_index}"> + + + + <%self.lib:td_label>Download Format + <%self.lib:td_input tab_index="${tab_index}" tab_inc="${2}"> + + +
+ + + + + + +<%def name="download_as_row(tab_index)"> + + <%self.lib:td_label>Download as + <%self.lib:td_input tab_index="${tab_index}" tab_inc="${2}"> + + +
+ + + + + + + +<%def name="include_sql_row(tab_index)"> + + <%self.lib:td_label for_id="include_sql_id"> + Include SQL in the download + + <%self.lib:td_input tab_index="${tab_index}"> + + + + + <%def name="table_rows(tab_index)"> <%parent:table_rows tab_index="${tab_index}" args="tab_index"> ## A blank table row for spacing ${self.sql_row(tab_index)} - ${self.file_input_row(tab_index)} @@ -145,6 +236,15 @@ <% tab_index.inc() %> +<%def name="controls(tab_index)"> + + ${self.file_input_row(tab_index)} + ${self.download_row(tab_index)} + ${self.download_as_row(tab_index)} + ${self.include_sql_row(tab_index)} +
+ + % if havecreds: <% tab_index = self.attr.TabIndex() %> ${self.main_form(tab_index, target=self.sql_results_target(), diff --git a/src/pgwui_sql/views/base.py b/src/pgwui_sql/views/base.py index ccf2f1f..bb02a2c 100644 --- a/src/pgwui_sql/views/base.py +++ b/src/pgwui_sql/views/base.py @@ -22,12 +22,31 @@ import pgwui_core.core import pgwui_core.forms import wtforms.fields +from pgwui_core.constants import ( + CHECKED, + UNCHECKED, + CSV, + TAB, + CSV_VALUE, + TAB_VALUE, +) +from pgwui_sql.constants import ( + ONE_FILE, + MANY_FILES, + ONE_FILE_VALUE, + MANY_FILES_VALUE, +) + @attrs.define(slots=False) class SQLInitialPost(pgwui_core.forms.UserInitialPost): sql = attrs.field(default='') upload_sql = attrs.field(default=False) sql_file = attrs.field(default=None) + download = attrs.field(default=False) + download_fmt = attrs.field(default=CSV) + download_as = attrs.field(default=ONE_FILE) + include_sql = attrs.field(default=True) class SQLWTForm(pgwui_core.forms.AuthWTForm): @@ -40,6 +59,17 @@ class SQLWTForm(pgwui_core.forms.AuthWTForm): 'Execute SQL from a file:', id='upload_sql_id') sql_file = wtforms.fields.FileField( 'File of SQL statements') + download = wtforms.fields.BooleanField( + 'Download', id='download_id') + download_fmt = wtforms.fields.RadioField( + 'Download Format:', choices=[('CSV', CSV), + ('Tab delimited', TAB)]) + download_as = wtforms.fields.RadioField( + 'Download as:', + choices=[('A single file with all results', ONE_FILE), + ("One file for each statement's results", MANY_FILES)]) + include_sql = wtforms.fields.BooleanField( + 'Include SQL in the download', id='include_sql_id') @attrs.define(slots=False) @@ -56,6 +86,10 @@ class SQLForm(pgwui_core.forms.UploadFormBaseMixin, sql_file = attrs.field(default=None) sql_file_read = attrs.field(default=False) filename = attrs.field(default=None) + download = attrs.field(default=False) + download_fmt = attrs.field(default=None) + download_as = attrs.field(default=None) + include_sql = attrs.field(default=True) def read(self): ''' @@ -86,10 +120,50 @@ class SQLForm(pgwui_core.forms.UploadFormBaseMixin, else: self['sql'] = self._form.sql.data + self['download'] = self._form.download.data + self['download_fmt'] = self._form.download_fmt.data + self['download_as'] = self._form.download_as.data + self['include_sql'] = self._form.include_sql.data + def write(self, result, errors): ''' Produces the dict pyramid will use to render the form. ''' response = super().write(result, errors) response['sql'] = self['sql'] + + if self['download']: + download_checked = CHECKED + else: + download_checked = UNCHECKED + response['download'] = download_checked + + if self['download_fmt'] == CSV: + csv_checked = CHECKED + tab_checked = UNCHECKED + else: + tab_checked = CHECKED + csv_checked = UNCHECKED + response['csv_checked'] = csv_checked + response['tab_checked'] = tab_checked + response['csv_value'] = CSV_VALUE + response['tab_value'] = TAB_VALUE + + response['download_as'] = self['download_as'] + if self['download_as'] == ONE_FILE: + one_file_checked = CHECKED + many_files_checked = UNCHECKED + else: + many_files_checked = CHECKED + one_file_checked = UNCHECKED + response['one_file_checked'] = one_file_checked + response['many_files_checked'] = many_files_checked + response['one_file_value'] = ONE_FILE_VALUE + response['many_files_value'] = MANY_FILES_VALUE + + if self['include_sql']: + include_sql_checked = CHECKED + else: + include_sql_checked = UNCHECKED + response['include_sql'] = include_sql_checked return response diff --git a/tests/templates/test_templates.py b/tests/templates/test_templates.py index 68ac7e7..60f8ed0 100644 --- a/tests/templates/test_templates.py +++ b/tests/templates/test_templates.py @@ -25,6 +25,16 @@ import pytest import pgwui_server.pgwui_server import pgwui_develop.testing import pyramid.testing +from pgwui_core.constants import ( + CHECKED, + UNCHECKED, + CSV_VALUE, + TAB_VALUE, +) +from pgwui_sql.constants import ( + ONE_FILE_VALUE, + MANY_FILES_VALUE, +) # A dict of "standard" settings pgwui_settings = {'dry_run': False, @@ -46,7 +56,17 @@ stock_template_args = { 'csrf_token': 'somecsrftoken', 'sql': 'select 1;', 'search_path': '"$user", somedb', - 'upload_sql': True + 'upload_sql': True, + 'download': False, + 'csv_value': CSV_VALUE, + 'tab_value': TAB_VALUE, + 'csv_checked': CHECKED, + 'tab_checked': UNCHECKED, + 'one_file_value': ONE_FILE_VALUE, + 'many_files_value': MANY_FILES_VALUE, + 'one_file_checked': CHECKED, + 'many_files_checked': UNCHECKED, + 'include_sql': True, } # The templates to test -- 2.34.1